package com.sojson.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sojson.config.exception.TransException;
import com.sojson.constant.Lock;
import com.sojson.dao.CouponDao;
import com.sojson.dao.CouponGetMethodDao;
import com.sojson.dao.CouponGoodsDao;
import com.sojson.dao.CouponModuleDao;
import com.sojson.dao.CouponStoreDao;
import com.sojson.dao.CouponUserDao;
import com.sojson.dao.UserCouponDao;
import com.sojson.entity.bo.CouponUseGoodsParam;
import com.sojson.entity.bo.CouponUseParam;
import com.sojson.entity.bo.CouponUseResponse;
import com.sojson.entity.po.Coupon;
import com.sojson.entity.po.CouponGoods;
import com.sojson.entity.po.CouponModule;
import com.sojson.entity.po.CouponStore;
import com.sojson.entity.po.CouponUser;
import com.sojson.entity.po.UserCoupon;
import com.sojson.entity.vo.CouponVo;
import com.sojson.entity.vo.UserCouponVo;
import com.sojson.enums.core.ECouponIsTogetherUse;
import com.sojson.enums.core.ECouponReducedMethod;
import com.sojson.enums.core.ECouponScopeGoods;
import com.sojson.enums.core.ECouponScopeModule;
import com.sojson.enums.core.ECouponScopeStore;
import com.sojson.enums.core.ECouponScopeUser;
import com.sojson.enums.core.ECouponStatus;
import com.sojson.enums.core.EGeneralYesNo;
import com.sojson.enums.core.EUserCouponStatus;
import com.sojson.service.CouponService;
import com.sojson.util.ArithUtil;
import com.sojson.util.DateUtil;
import com.sojson.util.RandomUtil;
import com.sojson.util.StringUtil;
import com.sojson.util.page.PageUtil;
import com.sojson.util.token.TokenUtil;

/**
 * 优惠券表Service实现类
 * 
 * @author liu
 * @date 2021-03-24
 */
@Service
public class CouponServiceImpl implements CouponService {

    @Autowired
    private CouponServiceImpl couponServiceImpl;
    @Resource
    private CouponDao couponDaoImpl;
    @Resource
    private CouponModuleDao couponModuleDaoImpl;
    @Resource
    private CouponStoreDao couponStoreDaoImpl;
    @Resource
    private CouponGoodsDao couponGoodsDaoImpl;
    @Resource
    private CouponUserDao couponUserDaoImpl;
    @Resource
    private UserCouponDao userCouponDaoImpl;
    @Resource
    private CouponGetMethodDao couponGetMethodDaoImpl;

    /**
     * 单条插入
     * 
     * @param coupon
     * @return
     */
    @Override
    @Transactional
    public int insert(Coupon coupon) {
        int insert = couponDaoImpl.insert(coupon);

        if (insert < 1) {
            throw new TransException("添加失败，请重试！");
        }
        Integer scopeModule = coupon.getScopeModule();
        List<String> moduleNos = coupon.getModuleNos();
        if ((ECouponScopeModule.APPOINT_SOME_YES.getCode() == scopeModule
            || ECouponScopeModule.APPOINT_SOME_NO.getCode() == scopeModule) && moduleNos.size() > 0) {
            CouponModule couponModule = new CouponModule();
            couponModule.insertInit(coupon);
            int insertAll = couponModuleDaoImpl.insertAll(couponModule);
            if (insertAll < 1) {
                throw new TransException("添加失败，请重试！");
            }
        }
        Integer scopeStore = coupon.getScopeStore();
        List<String> storeNos = coupon.getStoreNos();
        if ((ECouponScopeStore.APPOINT_SOME_YES.getCode() == scopeStore
            || ECouponScopeStore.APPOINT_SOME_NO.getCode() == scopeStore) && storeNos.size() > 0) {
            CouponStore couponStore = new CouponStore();
            couponStore.insertInit(coupon);
            int insertAll = couponStoreDaoImpl.insertAll(couponStore);
            if (insertAll < 1) {
                throw new TransException("添加失败，请重试！");
            }
        }
        Integer scopeGoods = coupon.getScopeGoods();
        List<String> goodsNos = coupon.getGoodsNos();
        if ((ECouponScopeGoods.APPOINT_SOME_YES.getCode() == scopeGoods
            || ECouponScopeGoods.APPOINT_SOME_NO.getCode() == scopeGoods) && goodsNos.size() > 0) {
            CouponGoods couponGoods = new CouponGoods();
            couponGoods.insertInit(coupon);
            int insertAll = couponGoodsDaoImpl.insertAll(couponGoods);
            if (insertAll < 1) {
                throw new TransException("添加失败，请重试！");
            }
        }
        Integer scopeUser = coupon.getScopeUser();
        List<String> userNos = coupon.getUserNos();
        if (StringUtil.isNotBlankObject(scopeUser) && (ECouponScopeUser.APPOINT_SOME_YES.getCode() == scopeUser
            || ECouponScopeUser.APPOINT_SOME_NO.getCode() == scopeUser) && userNos.size() > 0) {
            CouponUser couponUser = new CouponUser();
            couponUser.insertInit(coupon);
            int insertAll = couponUserDaoImpl.insertAll(couponUser);
            if (insertAll < 1) {
                throw new TransException("添加失败，请重试！");
            }
        }
        return insert;
    }

    /**
     * 通过id更新(局部更新)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateById(Coupon coupon) {
        Coupon findById = couponDaoImpl.findById(coupon.getId());
        if (StringUtil.isBlankObject(findById)) {
            return 0;
        }

        long currentTimeMillis = System.currentTimeMillis();
        if (findById.getStatus() == ECouponStatus.FAILURE.getCode()
            || currentTimeMillis < findById.getStartDate().getTime()
            || currentTimeMillis > findById.getEndDate().getTime()) {
            throw new TransException("优惠券已失效,不能解冻");
        }
        Integer type = coupon.getType();
        Integer reducedMethod = coupon.getReducedMethod();
        if (StringUtil.isNotBlankObject(type) && type.intValue() != findById.getType()
            || StringUtil.isNotBlankObject(reducedMethod) && reducedMethod.intValue() != findById.getReducedMethod()) {
            throw new TransException("优惠券类型不能修改！");
        }

        int updatePartialById = couponDaoImpl.updateById(coupon);
        return updatePartialById;
    }

    /**
     * 添加发放数量
     * 
     * @param coupon
     * @return
     */
    @Override
    public int addNumber(Coupon coupon) {
        int updateById = 0;

        synchronized (Lock.UPDATE_COUPON_NUMBER) {
            Integer findNumberById = couponDaoImpl.findNumberById(coupon.getId());
            if (StringUtil.isBlankObject(findNumberById)) {
                return 0;
            }

            coupon.setNumber(coupon.getNumber() + findNumberById);
            updateById = couponDaoImpl.updateById(coupon);
        }
        return updateById;
    }

    /**
     * 修改优惠券状态
     * 
     * @param coupon
     * @return
     * @throws SQLException
     */
    @Override
    public int updateStatus(Coupon coupon) {
        Coupon findById = couponDaoImpl.findById(coupon.getId());
        if (StringUtil.isBlankObject(findById)) {
            return 0;
        }

        long currentTimeMillis = System.currentTimeMillis();
        if (findById.getStatus() == ECouponStatus.FAILURE.getCode()
            || currentTimeMillis < findById.getStartDate().getTime()
            || currentTimeMillis > findById.getEndDate().getTime()) {
            throw new TransException("优惠券已失效,不能解冻");
        }

        int updatePartialById = couponDaoImpl.updateById(coupon);
        return updatePartialById;
    }

    /**
     * 关闭已结束的优惠券
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateStatusToEnd(CouponVo coupon) {
        return couponDaoImpl.updateStatusToEnd(coupon);
    }

    /**
     * 批量插入
     * 
     * @param coupon
     * @return
     */
    @Override
    public int insertList(Coupon coupon) {
        int insertList = couponDaoImpl.insertList(coupon.getCoupons());
        return insertList;
    }

    /**
     * 通过对象批量删除(物理删除)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int deleteByDto(Coupon coupon) {
        int deleteByDto = couponDaoImpl.deleteByDto(coupon);
        return deleteByDto;
    }

    /**
     * 统计全部数量
     * 
     * @return
     */
    @Override
    public int countAll() {
        int countAll = couponDaoImpl.countAll();
        return countAll;
    }

    /**
     * 查询所有
     * 
     * @return
     */
    @Override
    public List<Coupon> listAll() {
        List<Coupon> findAll = couponDaoImpl.listAll();
        return findAll;
    }

    /**
     * 根据对象统计数量
     * 
     * @param coupon
     * @return
     */
    @Override
    public int countByDto(Coupon coupon) {
        int countByDto = couponDaoImpl.countByDto(coupon);
        return countByDto;
    }

    /**
     * 根据对象查询
     * 
     * @param coupon
     * @return
     */
    @Override
    public List<Coupon> listByDto(Coupon coupon) {
        List<Coupon> findByDto = couponDaoImpl.listByDto(coupon);
        return findByDto;
    }

    /**
     * 通过id删除(物理删除)
     * 
     * @param id
     * @return
     */
    @Override
    @Transactional
    public int deleteById(Integer id) {
        int deleteById = couponDaoImpl.deleteById(id);
        return deleteById;
    }

    /**
     * 通过id数组删除(物理删除)
     * 
     * @param ids
     * @return
     */
    @Override
    public int deleteByIds(Integer[] ids) {
        int deleteByIds = couponDaoImpl.deleteByIds(ids);
        return deleteByIds;
    }

    /**
     * 通过id更新(全部更新)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateAllById(Coupon coupon) {
        int updateAllById = couponDaoImpl.updateAllById(coupon);
        return updateAllById;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateAllByIdList(Coupon coupon) {
        int updateAllByIdList = couponDaoImpl.updateAllByIdList(coupon);
        return updateAllByIdList;
    }

    /**
     * 通过id列表更新(全部更新)(更新内容不相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateDtoListAllById(Coupon coupon) {
        int updateDtoListAllById = couponDaoImpl.updateDtoListAllById(coupon.getCoupons());
        return updateDtoListAllById;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateByIdList(Coupon coupon) {
        int updateByIdList = couponDaoImpl.updateByIdList(coupon);
        return updateByIdList;
    }

    /**
     * 通过id列表更新(局部更新)(更新内容不相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateDtoListById(Coupon coupon) {
        int updateDtoListById = couponDaoImpl.updateDtoListById(coupon.getCoupons());
        return updateDtoListById;
    }

    /**
     * 通过id查询
     * 
     * @param id
     * @return
     */
    @Override
    public Coupon findById(Integer id) {
        Coupon findById = couponDaoImpl.findById(id);
        return findById;
    }

    /**
     * 通过id数组查询
     * 
     * @param ids
     * @return
     */
    @Override
    public List<Coupon> findByIds(Integer[] ids) {
        List<Coupon> findByIds = couponDaoImpl.findByIds(ids);
        return findByIds;
    }

    /**
     * 通过对象查询id列表
     * 
     * @param coupon
     * @return
     */
    @Override
    public List<Integer> findIdByDto(Coupon coupon) {
        List<Integer> findIdByDto = couponDaoImpl.findIdByDto(coupon);
        return findIdByDto;
    }

    /**
     * 通过no删除(物理删除)
     * 
     * @param no
     * @return
     */
    @Override
    public int deleteByNo(String no) {
        int deleteByNo = couponDaoImpl.deleteByNo(no);
        return deleteByNo;
    }

    /**
     * 通过no数组删除(物理删除)
     * 
     * @param nos
     * @return
     */
    @Override
    public int deleteByNos(String[] nos) {
        int deleteByNos = couponDaoImpl.deleteByNos(nos);
        return deleteByNos;
    }

    /**
     * 通过no更新(全部更新)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateAllByNo(Coupon coupon) {
        int updateAllByNo = couponDaoImpl.updateAllByNo(coupon);
        return updateAllByNo;
    }

    /**
     * 通过no列表更新(全部更新)(更新内容相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateAllByNoList(Coupon coupon) {
        int updateAllByNoList = couponDaoImpl.updateAllByNoList(coupon);
        return updateAllByNoList;
    }

    /**
     * 通过no列表更新(全部更新)(更新内容不相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateDtoListAllByNo(Coupon coupon) {
        int updateDtoListAllByNo = couponDaoImpl.updateDtoListAllByNo(coupon.getCoupons());
        return updateDtoListAllByNo;
    }

    /**
     * 通过no更新(局部更新)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateByNo(Coupon coupon) {
        int updateByNo = couponDaoImpl.updateByNo(coupon);
        return updateByNo;
    }

    /**
     * 通过no列表更新(局部更新)(更新内容相同)
     * 
     * @param coupon
     * @return
     */
    @Override
    public int updateByNoList(Coupon coupon) {
        int updateByNoList = couponDaoImpl.updateByNoList(coupon);
        return updateByNoList;
    }

    /**
     * 通过no列表更新(局部更新)(更新内容不相同)
     * 
     * @param coupons
     * @return
     */
    @Override
    public int updateDtoListByNo(Coupon coupon) {
        int updateDtoListByNo = couponDaoImpl.updateDtoListByNo(coupon.getCoupons());
        return updateDtoListByNo;
    }

    /**
     * 通过no查询
     * 
     * @param no
     * @return
     */
    @Override
    public Coupon findByNo(String no) {
        Coupon findByNo = couponDaoImpl.findByNo(no);
        return findByNo;
    }

    /**
     * 通过no数组查询
     * 
     * @param nos
     * @return
     */
    @Override
    public List<Coupon> findByNos(String[] nos) {
        List<Coupon> findByNos = couponDaoImpl.findByNos(nos);
        return findByNos;
    }

    /**
     * 通过对象查询no列表
     * 
     * @param coupon
     * @return
     */
    @Override
    public List<String> findNoByDto(Coupon coupon) {
        List<String> findNoByDto = couponDaoImpl.findNoByDto(coupon);
        return findNoByDto;
    }

    /**
     * 清空数据(物理清空)
     */
    @Override
    public int clear() {
        return couponDaoImpl.clear();
    }

    /**
     * 查询可领取的优惠券列表
     * 
     * @param coupon
     * @return
     */
    @Override
    public List<CouponVo> getCanReceive(CouponVo coupon) {
        // 优惠券列表
        List<CouponVo> listGet = couponDaoImpl.getCanReceive(coupon);

        Boolean isEnable = coupon.getIsEnable();
        if (StringUtil.isNotBlankObject(isEnable) && !isEnable) {
            String useUserNoVo = coupon.getUseUserNoVo();
            for (CouponVo couponVo : listGet) {
                Integer scopeUser = couponVo.getScopeUser();

                UserCoupon userCoupon = new UserCoupon();
                userCoupon.setCouponNo(couponVo.getNo());
                userCoupon.setBatchNo(couponVo.getBatchNo());
                userCoupon.setUserNo(useUserNoVo);
                int countByDto = userCouponDaoImpl.countByDto(userCoupon);
                if (countByDto > 0) {
                    couponVo.setIsEnable(false);
                    couponVo.setNoEnableMsg("已领取过此优惠券！");
                    continue;
                }

                String useNoMsg = "此优惠券只限特定用户领取";
                if (scopeUser == ECouponScopeUser.APPOINT.getCode()) {
                    if (!couponVo.getUseUserNo().equals(useUserNoVo)) {
                        couponVo.setIsEnable(false);
                        couponVo.setNoEnableMsg(useNoMsg);
                        continue;
                    }
                }
                if (scopeUser == ECouponScopeUser.APPOINT_SOME_YES.getCode()
                    || scopeUser == ECouponScopeUser.APPOINT_SOME_NO.getCode()) {
                    CouponUser couponUser = new CouponUser();
                    couponUser.setCouponNo(couponVo.getNo());
                    couponUser.setUserNo(useUserNoVo);
                    countByDto = couponUserDaoImpl.countByDto(couponUser);
                    if (scopeUser == ECouponScopeUser.APPOINT_SOME_YES.getCode()) {
                        if (countByDto < 1) {
                            couponVo.setIsEnable(false);
                            couponVo.setNoEnableMsg(useNoMsg);
                            continue;
                        }
                    } else if (scopeUser == ECouponScopeUser.APPOINT_SOME_NO.getCode()) {
                        if (countByDto > 0) {
                            couponVo.setIsEnable(false);
                            couponVo.setNoEnableMsg(useNoMsg);
                            continue;
                        }
                    }
                }
                if (StringUtil.isBlankObject(couponVo.getIsEnable())) {
                    couponVo.setIsEnable(true);
                }
            }
        }
        return listGet;
    }

    /**
     * 判断活动是否进行中
     * 
     * @param coupon
     * @param now
     */
    @Override
    public void isUnderway(Coupon coupon, long now) {
        if (StringUtil.isBlankObject(coupon)) {
            throw new TransException("此优惠券信息不存在！");
        }
        if (ECouponStatus.YES_LAUNCH.getCode() != coupon.getStatus()) {
            throw new TransException("优惠券未发布！");
        }
        if (coupon.getStartDate().getTime() > now) {
            throw new TransException("活动未开始！");
        }
        if (coupon.getEndDate().getTime() < now) {
            throw new TransException("活动已结束！");
        }
    }

    /**
     * 判断用户是否能领取
     * 
     * @param coupon
     * @throws IOException 
     */
    @Override
    public void isCanTakePartIn(Coupon coupon) throws IOException {
        // 当前用户ID
        String userNo = TokenUtil.getUserNo();

        // 查询用户是否可以领取
        Integer scopeUser = coupon.getScopeUser();
        if (scopeUser == ECouponScopeUser.APPOINT.getCode() && !coupon.getUseUserNo().equals(userNo)) {
            throw new TransException("此优惠券仅限特定用户领取！");
        } else if (scopeUser == ECouponScopeUser.APPOINT_SOME_YES.getCode()
            || scopeUser == ECouponScopeUser.APPOINT_SOME_NO.getCode()) {
            CouponUser couponUser = new CouponUser();
            couponUser.setCouponNo(coupon.getNo());
            couponUser.setUserNo(userNo);
            int countByDto = couponUserDaoImpl.countByDto(couponUser);

            if (scopeUser == ECouponScopeUser.APPOINT_SOME_YES.getCode() && countByDto < 1
                || scopeUser == ECouponScopeUser.APPOINT_SOME_NO.getCode() && countByDto > 0) {
                throw new TransException("此优惠券仅限特定用户领取！");
            }
        }

        // 查询用户领取奖励次数
        UserCoupon userCoupon = new UserCoupon();
        userCoupon.setCouponNo(coupon.getNo());
        userCoupon.setBatchNo(coupon.getBatchNo());
        userCoupon.setUserNo(userNo);
        int countByDto = userCouponDaoImpl.countByDto(userCoupon);
        // 判断是否满足活动要求的领取次数
        if (countByDto > 0) {
            throw new TransException("已领取过此优惠券！");
        }

        // 可领取的数量
        Integer number = coupon.getNumber();
        if (number < 1) {
            throw new TransException("优惠券已被领完！");
        }
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos 优惠券编号列表
     * @param moduleNo      模块编号
     * @param storeNo       店铺编号
     * @param goodsNo       商品编号
     * @param total         订单金额
     * @throws IOException 
     */
    @Override
    @Transactional
    public CouponUseResponse orderUse(String userCouponNos, String moduleNo, String storeNo, String goodsNo,
        BigDecimal total) throws IOException {
        if (StringUtil.isBlank(userCouponNos)) {
            CouponUseResponse couponUseResponse = new CouponUseResponse();
            couponUseResponse.setTotal(total);
            return couponUseResponse;
        }
        return couponServiceImpl.orderUse(userCouponNos.split(","), moduleNo, storeNo, goodsNo, total);
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos 优惠券编号列表
     * @param moduleNo      模块编号
     * @param storeNo       店铺编号
     * @param goodsNo       商品编号
     * @param total         订单金额
     * @throws IOException 
     */
    @Override
    @Transactional
    public CouponUseResponse orderUse(String[] userCouponNos, String moduleNo, String storeNo, String goodsNo,
        BigDecimal total) throws IOException {
        return couponServiceImpl.orderUse(Arrays.asList(userCouponNos), moduleNo, storeNo, goodsNo, total);
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos 优惠券编号列表
     * @param moduleNo      模块编号
     * @param storeNo       店铺编号
     * @param goodsNo       商品编号
     * @param total         订单金额
     * @throws IOException 
     */
    @Override
    @Transactional
    public CouponUseResponse orderUse(List<String> userCouponNos, String moduleNo, String storeNo, String goodsNo,
        BigDecimal total) throws IOException {
        CouponUseResponse couponUseResponse = new CouponUseResponse();

        int userCouponNosSize = userCouponNos.size();
        if (StringUtil.isBlankObject(userCouponNos) || userCouponNosSize < 1) {
            couponUseResponse.setTotal(total);
            return couponUseResponse;
        }

        Set<String> hashSet = new HashSet<>(userCouponNos);
        if (hashSet.size() != userCouponNosSize) {
            throw new TransException("优惠券单个订单只能使用一次！");
        }

        // 获取优惠券信息
        UserCouponVo userCouponParam = new UserCouponVo();
        userCouponParam.setNos(userCouponNos);
        userCouponParam.setUserNo(TokenUtil.getUserNo());
        userCouponParam.setUseModuleNo(moduleNo);
        userCouponParam.setUseStoreNo(storeNo);
        userCouponParam.setUseGoodsNo(goodsNo);
        List<UserCouponVo> infoByNos = userCouponDaoImpl.getInfoIsUseByNos(userCouponParam);
        int size = infoByNos.size();
        // 排序后的折扣优惠券信息
        List<UserCouponVo> sortDiscount = new ArrayList<>(size);
        // 满减优惠券信息
        List<UserCouponVo> fixed = new ArrayList<>();
        // 判断优惠券是否存在
        if (StringUtil.isBlankObject(infoByNos)) {
            throw new TransException("优惠券不存在！");
        }
        if (userCouponNosSize != size) {
            throw new TransException("优惠券不能在此商品上使用！");
        }
        for (UserCouponVo userCouponVo : infoByNos) {
            Coupon coupon = userCouponVo.getCoupon();
            if (StringUtil.isBlankObject(coupon)) {
                throw new TransException("优惠券信息不存在！");
            }

            // 判断是否在使用日期内
            Date startDate = coupon.getStartDate();
            Date endDate = coupon.getEndDate();
            long nowLong = DateUtil.nowLong();
            if (nowLong < startDate.getTime() || nowLong > endDate.getTime()) {
                throw new TransException("优惠券不在使用日期内！");
            }

            // 判断优惠券状态
            if (ECouponStatus.YES_LAUNCH.getCode() != coupon.getStatus()
                || EUserCouponStatus.USE_NO.getCode() != userCouponVo.getStatus()) {
                throw new TransException("优惠券不可用！");
            }

            // 优惠券门槛
            BigDecimal doorsill = coupon.getDoorsill();
            // 判断是否满足优惠券门槛
            if (total.subtract(doorsill).doubleValue() < 0) {
                throw new TransException("优惠券不可用！");
            }

            // 优惠券排序
            Integer reducedMethod = coupon.getReducedMethod();
            if (reducedMethod == ECouponReducedMethod.DISCOUNT.getCode()) {
                sortDiscount.add(userCouponVo);
            } else {
                fixed.add(userCouponVo);
            }
        }
        if (userCouponNosSize > 1) {
            for (UserCouponVo userCouponVo : infoByNos) {
                Coupon coupon = userCouponVo.getCoupon();
                if (coupon.getIsTogetherUse() == ECouponIsTogetherUse.NO.getCode()) {
                    throw new TransException("该优惠券不允许与其他优惠券同时使用！");
                }
            }
        }

        // 排序
        sortDiscount.sort(new Comparator<UserCouponVo>() {
            @Override
            public int compare(UserCouponVo o1, UserCouponVo o2) {
                return o1.getCoupon().getDiscount().intValue() - o2.getCoupon().getDiscount().intValue();
            }
        });
        // 合并
        sortDiscount.addAll(fixed);

        // 使用日期
        Date nowDate = DateUtil.nowDate();
        // 要修改状态的集合
        List<UserCoupon> arrayList = new ArrayList<>();
        StringBuilder couponNos = new StringBuilder();
        StringBuilder couponTotals = new StringBuilder();
        for (UserCouponVo userCouponVo : sortDiscount) {
            Coupon coupon = userCouponVo.getCoupon();

            // 计算优惠金额
            BigDecimal couponPrice = null;
            Integer reducedMethod = coupon.getReducedMethod();
            if (reducedMethod == ECouponReducedMethod.FIXED.getCode()) {
                couponPrice = coupon.getPrice();
            } else if (reducedMethod == ECouponReducedMethod.DISCOUNT.getCode()) {
                int totalInt = ArithUtil.bigDollarToIntPenny(total);
                Integer discount = coupon.getDiscount();
                couponPrice = ArithUtil.intPennyToBigDollar(totalInt * discount.intValue() / 100);

                // 是否设置折扣上限
                Integer isDiscountCeiling = coupon.getIsDiscountCeiling();
                if (StringUtil.isNotBlankObject(isDiscountCeiling)
                    && isDiscountCeiling == EGeneralYesNo.YES.getCode()) {
                    BigDecimal discountCeiling = coupon.getDiscountCeiling();
                    // 如果优惠金额大于折扣上限就把优惠金额设为上限金额
                    if (discountCeiling.doubleValue() < couponPrice.doubleValue()) {
                        couponPrice = discountCeiling;
                    }
                }
            } else if (reducedMethod == ECouponReducedMethod.RANDOM.getCode()) {
                BigDecimal randomStart = coupon.getRandomStart();
                BigDecimal randomEnd = coupon.getRandomEnd();
                int randomStartInt = ArithUtil.bigDollarToIntPenny(randomStart);
                int randomEndInt = ArithUtil.bigDollarToIntPenny(randomEnd);
                int nextInt = RandomUtil.nextInt(randomStartInt, randomEndInt);
                couponPrice = ArithUtil.intPennyToBigDollar(nextInt);
            }

            // 金额减去优惠金额
            if (total.doubleValue() <= 0) {
                couponPrice = new BigDecimal("0");
            } else {
                BigDecimal subtract = total.subtract(couponPrice);
                if (subtract.doubleValue() < 0) {
                    couponPrice = total;
                    total = new BigDecimal("0");
                } else {
                    total = subtract;
                }
            }

            String no = userCouponVo.getNo();
            UserCoupon userCoupon = new UserCoupon();
            userCoupon.setNo(no);
            userCoupon.setStatus(EUserCouponStatus.USE_YES.getCode());
            userCoupon.setUseDate(nowDate);
            userCoupon.setModuleNo(moduleNo);
            userCoupon.setStoreNo(storeNo);
            userCoupon.setGoodsNo(goodsNo);
            userCoupon.setTotal(couponPrice);
            arrayList.add(userCoupon);
            couponNos.append(no).append(",");
            couponTotals.append(couponPrice).append(",");
        }

        // 修改优惠券状态
        for (UserCoupon userCoupon : arrayList) {
            int updateByNo = userCouponDaoImpl.updateByNo(userCoupon);
            if (updateByNo < 1) {
                throw new TransException("优惠券状态修改失败，请重试！");
            }
        }

        couponUseResponse.setTotal(total);
        couponUseResponse.setCouponNos(couponNos.substring(0, couponNos.lastIndexOf(",")));
        couponUseResponse.setTotalSplit(couponTotals.substring(0, couponTotals.lastIndexOf(",")));
        return couponUseResponse;
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @throws IOException 
     */
    @Override
    @Transactional
    public CouponUseResponse orderUse(String userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total) throws IOException {
        if (StringUtil.isBlank(userCouponNos)) {
            CouponUseResponse couponUseResponse = new CouponUseResponse();
            couponUseResponse.setTotal(total);
            return couponUseResponse;
        }
        return couponServiceImpl.orderUse(userCouponNos.split(","), moduleNo, storeNo, couponUseGoodsParams, total);
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @throws IOException 
     */
    @Override
    @Transactional
    public CouponUseResponse orderUse(String[] userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total) throws IOException {
        return couponServiceImpl.orderUse(Arrays.asList(userCouponNos), moduleNo, storeNo, couponUseGoodsParams, total);
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @throws IOException 
     */
    @Override
    @Transactional
    public CouponUseResponse orderUse(List<String> userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total) throws IOException {
        return couponServiceImpl.orderUse(userCouponNos, moduleNo, storeNo, couponUseGoodsParams, total, true);
    }

    /**
     * 订单计算优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @throws IOException 
     */
    @Override
    public CouponUseResponse orderArith(String userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total) throws IOException {
        if (StringUtil.isBlank(userCouponNos)) {
            CouponUseResponse couponUseResponse = new CouponUseResponse();
            couponUseResponse.setTotal(total);
            return couponUseResponse;
        }
        return couponServiceImpl.orderArith(userCouponNos.split(","), moduleNo, storeNo, couponUseGoodsParams, total);
    }

    /**
     * 订单计算优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @throws IOException 
     */
    @Override
    public CouponUseResponse orderArith(String[] userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total) throws IOException {
        return couponServiceImpl.orderArith(Arrays.asList(userCouponNos), moduleNo, storeNo, couponUseGoodsParams,
            total);
    }

    /**
     * 订单计算优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @throws IOException 
     */
    @Override
    public CouponUseResponse orderArith(List<String> userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total) throws IOException {
        return couponServiceImpl.orderUse(userCouponNos, moduleNo, storeNo, couponUseGoodsParams, total, false);
    }

    /**
     * 订单使用优惠券
     * 
     * @param userCouponNos         优惠券编号列表
     * @param moduleNo              模块编号
     * @param storeNo               店铺编号
     * @param couponUseGoodsParams  商品信息
     * @param total                 订单金额
     * @param isUse                 是否使用(false为只计算)
     * @throws IOException 
     */
    @Transactional
    public CouponUseResponse orderUse(List<String> userCouponNos, String moduleNo, String storeNo,
        List<CouponUseGoodsParam> couponUseGoodsParams, BigDecimal total, Boolean isUse) throws IOException {
        CouponUseResponse couponUseResponse = new CouponUseResponse();
        couponUseResponse.setTotalOriginal(total);

        int userCouponNosSize = userCouponNos.size();
        if (StringUtil.isBlankObject(userCouponNos) || userCouponNosSize < 1) {
            couponUseResponse.setTotal(total);
            return couponUseResponse;
        }

        Set<String> hashSet = new HashSet<>(userCouponNos);
        if (hashSet.size() != userCouponNosSize) {
            throw new TransException("优惠券单个订单只能使用一次！");
        }

        // 获取优惠券信息
        CouponUseParam couponUseParam = new CouponUseParam();
        couponUseParam.setUserCouponNos(userCouponNos);
        couponUseParam.setUseModuleNo(moduleNo);
        couponUseParam.setUseStoreNo(storeNo);
        couponUseParam.setUserNo(TokenUtil.getUserNo());
        couponUseParam.setCouponUseGoodss(couponUseGoodsParams);
        couponUseParam.init();
        PageUtil.all(couponUseParam);
        List<UserCouponVo> infoByNos = userCouponDaoImpl.list(couponUseParam);
        int size = infoByNos.size();
        // 排序后的折扣优惠券信息
        List<UserCouponVo> sortDiscount = new ArrayList<>(size);
        // 满减优惠券信息
        List<UserCouponVo> fixed = new ArrayList<>();
        // 判断优惠券是否存在
        if (StringUtil.isBlankObject(infoByNos)) {
            throw new TransException("优惠券不存在！");
        }
        if (userCouponNosSize != size) {
            throw new TransException("优惠券不能在此商品上使用！");
        }
        for (UserCouponVo userCouponVo : infoByNos) {
            Coupon coupon = userCouponVo.getCoupon();
            if (StringUtil.isBlankObject(coupon)) {
                throw new TransException("优惠券信息不存在！");
            }

            // 判断是否在使用日期内
            Date startDate = coupon.getStartDate();
            Date endDate = coupon.getEndDate();
            long nowLong = DateUtil.nowLong();
            if (nowLong < startDate.getTime() || nowLong > endDate.getTime()) {
                throw new TransException("优惠券不在使用日期内！");
            }

            // 判断优惠券状态
            if (ECouponStatus.YES_LAUNCH.getCode() != coupon.getStatus()
                || EUserCouponStatus.USE_NO.getCode() != userCouponVo.getStatus()) {
                throw new TransException("优惠券不可用！");
            }

            // 优惠券门槛
            BigDecimal doorsill = coupon.getDoorsill();
            // 判断是否满足优惠券门槛
            if (total.subtract(doorsill).doubleValue() < 0) {
                throw new TransException("优惠券不可用！");
            }

            // 优惠券排序
            Integer reducedMethod = coupon.getReducedMethod();
            if (reducedMethod == ECouponReducedMethod.DISCOUNT.getCode()) {
                sortDiscount.add(userCouponVo);
            } else {
                fixed.add(userCouponVo);
            }
        }
        if (userCouponNosSize > 1) {
            for (UserCouponVo userCouponVo : infoByNos) {
                Coupon coupon = userCouponVo.getCoupon();
                if (coupon.getIsTogetherUse() == ECouponIsTogetherUse.NO.getCode()) {
                    throw new TransException("该优惠券不允许与其他优惠券同时使用！");
                }
            }
        }

        // 排序
        sortDiscount.sort(new Comparator<UserCouponVo>() {
            @Override
            public int compare(UserCouponVo o1, UserCouponVo o2) {
                return o1.getCoupon().getDiscount().intValue() - o2.getCoupon().getDiscount().intValue();
            }
        });
        // 合并
        sortDiscount.addAll(fixed);

        // 使用日期
        Date nowDate = DateUtil.nowDate();
        // 要修改状态的集合
        List<UserCoupon> arrayList = new ArrayList<>();
        StringBuilder couponNos = new StringBuilder();
        StringBuilder couponTotals = new StringBuilder();
        for (UserCouponVo userCouponVo : sortDiscount) {
            Coupon coupon = userCouponVo.getCoupon();

            // 计算优惠金额
            BigDecimal couponPrice = null;
            Integer reducedMethod = coupon.getReducedMethod();
            if (reducedMethod == ECouponReducedMethod.FIXED.getCode()) {
                couponPrice = coupon.getPrice();
            } else if (reducedMethod == ECouponReducedMethod.DISCOUNT.getCode()) {
                int totalInt = ArithUtil.bigDollarToIntPenny(total);
                Integer discount = coupon.getDiscount();
                couponPrice = ArithUtil.intPennyToBigDollar(totalInt * discount.intValue() / 100);

                // 是否设置折扣上限
                Integer isDiscountCeiling = coupon.getIsDiscountCeiling();
                if (StringUtil.isNotBlankObject(isDiscountCeiling)
                    && isDiscountCeiling == EGeneralYesNo.YES.getCode()) {
                    BigDecimal discountCeiling = coupon.getDiscountCeiling();
                    // 如果优惠金额大于折扣上限就把优惠金额设为上限金额
                    if (discountCeiling.doubleValue() < couponPrice.doubleValue()) {
                        couponPrice = discountCeiling;
                    }
                }
            } else if (reducedMethod == ECouponReducedMethod.RANDOM.getCode()) {
                BigDecimal randomStart = coupon.getRandomStart();
                BigDecimal randomEnd = coupon.getRandomEnd();
                int randomStartInt = ArithUtil.bigDollarToIntPenny(randomStart);
                int randomEndInt = ArithUtil.bigDollarToIntPenny(randomEnd);
                int nextInt = RandomUtil.nextInt(randomStartInt, randomEndInt);
                couponPrice = ArithUtil.intPennyToBigDollar(nextInt);
            }

            // 金额减去优惠金额
            if (total.doubleValue() <= 0) {
                couponPrice = new BigDecimal("0");
            } else {
                BigDecimal subtract = total.subtract(couponPrice);
                if (subtract.doubleValue() < 0) {
                    couponPrice = total;
                    total = new BigDecimal("0");
                } else {
                    total = subtract;
                }
            }

            String no = userCouponVo.getNo();
            couponNos.append(no).append(",");
            couponTotals.append(couponPrice).append(",");
            if (isUse) {
                UserCoupon userCoupon = new UserCoupon();
                userCoupon.setNo(no);
                userCoupon.setStatus(EUserCouponStatus.USE_YES.getCode());
                userCoupon.setUseDate(nowDate);
                userCoupon.setModuleNo(moduleNo);
                userCoupon.setStoreNo(storeNo);
                userCoupon.setTotal(couponPrice);
                arrayList.add(userCoupon);
            }
        }

        if (isUse) {
            // 修改优惠券状态
            for (UserCoupon userCoupon : arrayList) {
                int updateByNo = userCouponDaoImpl.updateByNo(userCoupon);
                if (updateByNo < 1) {
                    throw new TransException("优惠券状态修改失败，请重试！");
                }
            }
        }

        couponUseResponse.setTotal(total);
        couponUseResponse
            .setTotalCoupon(ArithUtil.subBig(couponUseResponse.getTotalOriginal(), couponUseResponse.getTotal()));
        couponUseResponse.setCouponNos(couponNos.substring(0, couponNos.lastIndexOf(",")));
        couponUseResponse.setTotalSplit(couponTotals.substring(0, couponTotals.lastIndexOf(",")));
        return couponUseResponse;
    }

    /**
     * 删除优惠券
     * 
     * @param coupon
     * @return
     */
    @Override
    public int delete(CouponVo coupon) {
        return couponDaoImpl.delete(coupon);
    }

}